package com.example.service;

import com.baomidou.mybatisplus.service.IService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.example.entity.Account;
import com.example.entity.PayRecord;
import com.example.entity.Payment;
import com.example.mapper.AccountMapper;
import com.example.mapper.PaymentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class IPayment extends ServiceImpl<PaymentMapper, Payment> implements IService<Payment> {

    @Autowired
    PaymentMapper paymentMapper;

    @Autowired
    AccountMapper accountMapper;

    @Autowired
    IAccount iAccount;

    @Autowired
    IPayRecord iPayRecord;

//    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public void pay(Payment payment) throws Exception {
        paymentMapper.insert(payment);
        updateAccount(payment);
        // 同一个类里面方法互相调用
        // 上面两行按照事务注解 应该是 不管 insert 失败与否，updateAccount不报错情况下都会执行成功并且提交
        // 但是现在 下面方法的注解失效了，因为调用的是当前类的方法，不是代理类的方法
        // 处理： 启动类 添加暴露事务代理类的注解 @EnableAspectJAutoProxy(exposeProxy = true)，然后按下面
//        ((IPayment) AopContext.currentProxy()).updateAccount(payment);

    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateAccount(Payment payment) throws Exception {
        Account account = new Account();
        account.setUserId(payment.getUserId());
        Account account1 = accountMapper.selectOne(account);
        if (account1 != null && account1.getBalance() >= payment.getAmount()) {
            account1.setBalance(account1.getBalance() - payment.getAmount());
            accountMapper.updateById(account1);
        } else {
//             transaction 源码只认 RuntimeException 和 Error 才会进行 rollback
//             ex instanceof RuntimeException  || ex instanceof Error
//            throw new RuntimeException(" update account  fail");

            // 接下来我们处理 抛出的是 exception 的话怎样回滚   指定回滚异常类型  rollbackFor = Exception.class
            throw new Exception(" update account  fail");
        }
    }


    /**
     * 不管是否购买成功，都会记录购买日志，添加 payRecord 一定要让成功
     */
    @Transactional(rollbackFor = Exception.class)
    public void payAndRecord(Payment payment) throws Exception {
        int payStatus = 0;
        try {
            paymentMapper.insert(payment);
            iAccount.updateAccount(payment);
            payStatus = 1;
        } finally {
            PayRecord payRecord = new PayRecord();
            payRecord.setPayAmount(payment.getAmount());
            payRecord.setPayName(payment.getName());
            payRecord.setPayUserId(payment.getUserId());
            payRecord.setPayStatus(payStatus);
            iPayRecord.addRecord(payRecord);
        }

    }

}
